/**
 * Copyright (c) 2011 
 */

package edu.ucsb.android.APMap;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.OverlayItem;

import edu.ucsb.APMap.util.APInfo;

public class ApMapActivity extends MapActivity implements LocationListener{
	
	MapView gMapView;
	MapController mapcontroller;
	MyLocationOverlay mMyLocationOverlay;
	View popBubbleView;
	Drawable drawable;
	BubbleItemizedOverlay itemizedOverlay;
	LocationManager locationManager;
	TCPClient tcpClient;
	WifiManager wifiManager;
	private String wifiInfo = "Detecting...";
	
	private Timer fileTimer = new Timer(true);
	    
    Handler apHandler = new Handler() {  
		@Override
		public void handleMessage(Message message) { 
			itemizedOverlay.clearOverlay();
			try{
				@SuppressWarnings("unchecked")
				LinkedList<APInfo> apInfo = (LinkedList<APInfo>) message.obj;
				for(APInfo oneAp: apInfo){
					GeoPoint gp1 = new GeoPoint((int) (oneAp.getLatitude() * 1000000), 
												(int) (oneAp.getLongtitude() * 1000000));
					//setupApOverlay(gp1, R.drawable.wifi);
					OverlayItem overlayitem = new OverlayItem(gp1, oneAp.getBSSID(), oneAp.getCapabilities());
					itemizedOverlay.addOverlay(overlayitem);
				}
				gMapView.getOverlays().add(itemizedOverlay);
		        
	        } catch (Exception e) {
	        	Log.e("APMapClient", "################" + e + "!!!!!!!!!!!!");
	        }
    	}  
    }; 
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        iniMap();
        wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        //new Thread(new UdpReceiver(apHandler)).start();
        //new Thread(new UdpSender("REQ")).start();
        tcpClient = new TCPClient(apHandler, checkWifi());
        iniLocationManager();
        
        //for experiment, after 3s first run, run every 60mins
        fileTimer.schedule(fileTimerTask, 3000, 60*60*1000);
        
    }
    
    private void iniMap(){
    	// Creating and initializing Map
    	gMapView = (MapView) findViewById(R.id.mapview);
    	//get MapController that helps to set/get location, zoom etc.
    	mapcontroller = gMapView.getController();
    	
        //get current location
    	mMyLocationOverlay = new MyLocationOverlay(this, gMapView);
		mMyLocationOverlay.enableMyLocation();
		mMyLocationOverlay.runOnFirstFix(
		    new Runnable() {
		        public void run() {
		        	mapcontroller.animateTo(mMyLocationOverlay.getMyLocation());
		        	mapcontroller.setZoom(12);
		        }
		    });
		
		gMapView.getOverlays().add(mMyLocationOverlay);
		
		gMapView.setClickable(true);
		gMapView.setEnabled(true);
		gMapView.setSatellite(true);
		gMapView.setTraffic(false);
		gMapView.setStreetView(false);
		
		// start out with a general zoom
		mapcontroller.setZoom(18);
		
		// add pop bubble view
		popBubbleView = View.inflate(this, R.layout.overlay_pop_bubble, null);
		gMapView.addView( popBubbleView,
				new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT, MapView.LayoutParams.WRAP_CONTENT,
				null, MapView.LayoutParams.BOTTOM_CENTER));
		popBubbleView.setVisibility(View.GONE);
		
		drawable = this.getResources().getDrawable(R.drawable.wifi);
		itemizedOverlay = new BubbleItemizedOverlay(drawable);
		itemizedOverlay.setOnFocusChangeListener(onFocusChangeListener);
		
		gMapView.invalidate();
    }
    
    private void iniLocationManager(){
    	boolean gpsEnabled = false;
    	boolean networkEnabled = false;
    	locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
    	try{
        	gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        	Log.d("GPSService", "########### gps enabled");
        } catch(Exception ex){}
        try{
        	networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        	Log.d("GPSService", "########### network enabled");
        } catch(Exception ex){}
        
        //don't start listeners if no provider is enabled
        if(!gpsEnabled && !networkEnabled){
        	Log.w("GPSService", "############ gsp and network location are not enalbed");
        	return;
        }
          
        //every 2.5min, 10m
        if(gpsEnabled){
        	locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 150000, 10, this);
        }
        if(networkEnabled){
        	locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 150000, 10, this);
        } 
        
    }
    
	@Override
    protected void onDestroy() {
        super.onDestroy();
        fileTimer.cancel();
        //this.stopService(new Intent(this, GPSService.class));
        Log.d("Activity", "############ activity is destroyed");
        //android.os.Process.killProcess(android.os.Process.myTid());
        System.exit(0);
    }

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}
	
	@Override
	public void onLocationChanged(Location location) {
		if(checkWifi()){
			Log.d("checkWifi", "########## true about to send REQ");
			tcpClient.sendREQ(location);
		}
		scanApAndSaveToFile(location);
	}

	@Override
	public void onProviderDisabled(String provider) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onProviderEnabled(String provider) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub
		
	}
	
	private class BubbleItemizedOverlay extends ItemizedOverlay<OverlayItem> {
		private ArrayList<OverlayItem> mapOverlays = new ArrayList<OverlayItem>();
		
		public BubbleItemizedOverlay(Drawable defaultMarker) {
			super(boundCenterBottom(defaultMarker));
		}
		
		@Override
		protected OverlayItem createItem(int i) {
			return mapOverlays.get(i);
		}
		
		@Override
		public int size() {
			return mapOverlays.size();
		}
		
		@Override
		protected boolean onTap(int index) {
			OverlayItem item = mapOverlays.get(index);
			
			return true;
		}
		
		public void addOverlay(OverlayItem overlay) {
			mapOverlays.add(overlay);
			this.populate();
		}
		
		public void clearOverlay() {
			mapOverlays.clear();
		}
	}
	
	private ItemizedOverlay.OnFocusChangeListener onFocusChangeListener = new ItemizedOverlay.OnFocusChangeListener() {
		@Override
		public void onFocusChanged(ItemizedOverlay overlay, OverlayItem newFocus) {
			Log.d("Map", "########### onFocusChanged in Done");
			
			if (popBubbleView != null) {
				// hide the old pop bubble
				popBubbleView.setVisibility(View.GONE);
				
				if (newFocus != null) {
					TextView titleTextView = (TextView) popBubbleView.findViewById(R.id.poptitle);
					titleTextView.setTextColor(Color.BLUE);
					titleTextView.setText(newFocus.getTitle());
				    TextView contentTextView = (TextView) popBubbleView.findViewById(R.id.poptext);
				    contentTextView.setTextColor(Color.BLACK);
				    contentTextView.setText(newFocus.getSnippet());
				    
				    MapView.LayoutParams layoutParams = (MapView.LayoutParams) popBubbleView.getLayoutParams();
				    layoutParams.point = newFocus.getPoint();
				    gMapView.updateViewLayout(popBubbleView, layoutParams);
				    popBubbleView.setVisibility(View.VISIBLE);
				} else {
					Log.d("Map", "########### onFocusChanged: newFocus == null");
				}
			    
			} else {
				Log.d("Map", "########### onFocusChanged: popBubbleView == null");
			}
			
			Log.d("Map", "########### onFocusChanged Done");
		}
	};
	
	private void scanApAndSaveToFile(Location myLocation){
		FileOP fileOP = FileOP.getFileOP();
		wifiInfo = scanAP();
		fileOP.writeToFile("Beginning_LOC" + "\n" 
				+ myLocation.getLatitude() + "," 
				+ myLocation.getLongitude() + "," 
				+ myLocation.getAltitude() 
				+ "\n" + "Ending_LOC" + "\n" 
				+ "Beginnig_TS" + "\n" + getTimestamp() 
				+ "\n" + "Ending_TS" + "\n"
				+ wifiInfo);
	}
	
	private String scanAP(){
		Log.d("GPSService", "########### scan wifi");
		wifiManager.startScan();
		List<ScanResult> results = wifiManager.getScanResults();
		if(results == null || results.size() ==0)
			return "No AP detected";
		for(ScanResult res : results){
			if(res.capabilities == null || res.capabilities.equals("")){
				res.capabilities = "NO_AUTH";
			}
		}
		StringBuffer wifiInfo = new StringBuffer();
		//wifiInfo.append(results.size() + " APs are detected" + "\n");
		wifiInfo.append("Beginning_APs" + "\n");
		for(ScanResult result : results){
			wifiInfo.append(result.SSID + "," 
					+ result.level + "," 
					+ result.frequency + "," 
					+ result.BSSID + "," 
					+ result.capabilities + "\n");
		}
		wifiInfo.append("Ending_APs" + "\n");
		return wifiInfo.toString();
	}
	
	private long getTimestamp() {
		long timestamp = System.currentTimeMillis()/1000;
		return timestamp;
	}
	

	private TimerTask fileTimerTask = new TimerTask() {
		
		public void run (){
			if(checkWifi()){
	        	Log.d("checkWifi", "########## true about to send files");
				// get file size
				File sdRoot = Environment.getExternalStorageDirectory();
				long fileTime = 0;
				Date date = new Date();
				long currTime = date.getTime(); 
	
				if (sdRoot.isDirectory()) {
					File[] listOfFiles = sdRoot.listFiles();
					
					if (listOfFiles != null) {
						for (File file : listOfFiles) {
							if (file.isFile()) {
								if (file.getName().startsWith("ap-") && file.getName().endsWith(".txt")) {
									fileTime = file.lastModified();
									
									// if the file is modified within an hour, skip it
									if (currTime - fileTime > 3600 * 1000) {
										Log.d("APMapClient", "#########     sending file: " + file.getAbsolutePath());
										tcpClient.sendFile(file.getAbsolutePath());
									} 
									file.delete();
								}
							}
						}
						
					}
				}
				
				Log.d("APMapClient", "################ timer !!!!!!!!!!!!");
			}
		}
	};
	
	private boolean checkWifi(){
		NetworkInfo info = (NetworkInfo) ((ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo(); 
		
		if (info == null || !info.isConnected()) { 
		    return false; 
		} 
		if (info.isRoaming()) { 
		    // here is the roaming option you can change it if you want to 
		    // disable internet while roaming, just return false 
		    return false; 
		} 
		return true; 
	}
	
	/*
	 * used for wifi icon before
	public void setupApOverlay(GeoPoint markerPoint, int flag){
		Log.d("Map", "########### set wifi overlay");
		Bitmap bmp = BitmapFactory.decodeResource(getResources(), flag);
		Point deviation = new Point(-32,-32);
		ApOverlay apOverlay = new ApOverlay(markerPoint, bmp, deviation);
		gMapView.getOverlays().add(apOverlay);
	}
	
	private class ApOverlay extends Overlay {

    	private GeoPoint point = null;
		private Bitmap bmp = null;
		private Point deviation = null;
		
		public ApOverlay(GeoPoint point, Bitmap bmp, Point deviation){
			this.point = point;
			this.bmp = bmp;
			this.deviation = deviation;
		}
		
		public void draw(Canvas canvas, MapView mapView, boolean shadow) {
			if(!shadow){
				Projection projection = mapView.getProjection();
				if(point != null && bmp != null){
					Point pos = projection.toPixels(point, null);
					canvas.drawBitmap(bmp, pos.x + deviation.x, pos.y + deviation.y, null);
				}
			}
		}
		
		public boolean onTap(GeoPoint p, MapView mapView) {
			return super.onTap(p, mapView);
		}
	}
	*/

}